<?php

declare(strict_types=1);
namespace Service\StorageService;


use Service\BaseService;
use Service\Code\Normal;
use App\Model\BbcModel\Storage;
use App\Model\BbcModel\Mnuser;
use App\Model\BbcModel\Goods;
use App\Model\BbcModel\MnStoreGoods;
use App\Model\BbcModel\GoodsBatch;
use App\Model\BbcModel\GoodsBrand;
use Service\EsService\EsPublishMsgService;
use App\Model\BbcModel\StockLog;
use App\Model\BbcModel\AveragePriceLog;
use Service\GoodsService\GoodsBatchService;
use Service\UserService\MnUserService;
use Service\GoodsService\MnGoodsService;
use Service\StorageService\StockSearchHistoryService;
use App\Model\BbcModel\PdaStockLoc;

class StockService extends BaseService
{
    
    /**
     * 增加库存
     * @param int $cid
     * @param int $mn_sid
     * @param array $extra
     * @return type
     */
    public function addStock(int $cid,int $mn_sid,array $extra)
    {
        $goods_id   =$extra['goods_id'];
        $bill_type  =$extra['bill_type'];
        $bill_id    =$extra['bill_id'];
        $bill_code  =$extra['bill_code'];
        $num        =$extra['num'];
        $batch_no   =$extra['batch_no'];
        $expire     =$extra['expire']=='0000-00-00'?0:$extra['expire'];
        $time       =$extra['time']??time();
        $stock_loc  =$extra['stock_loc']??0;
        $storage= Storage::instance()->info(['df'=>0,'cid'=>$cid,'mn_sid'=>$mn_sid,'store_type'=>0]);
        if(!$storage){
            return Normal::returnCode(Normal::FAIL,'仓库不存在');
        }
        $spec_list=[[
            "spec_num"=>1,
            "specName"=>"1件装",
            "price"=>"",
            "expired_date"=>isset($expire['expire'])?$expire['expire']:'',
            "make_date"=>"",
            "priceSettlement"=>"",
            "priceMarket"=>""
        ]];
        $mn_user= Mnuser::instance()->info(['id'=>$mn_sid]);
        $mnstoregoodsre= MnStoreGoods::instance()->info(['mn_sid'=>$mn_sid,'goods_id'=>$goods_id]);
        $goodsdata= Goods::instance()->info(['id'=>$goods_id]);
        $mnStoreGoodsQuantity=$mnstoregoodsre['quantity']??0;
        $mnStoreGoodsNum=$mnstoregoodsre['num']??0;
        $new_quantity=bcadd((string)$num, (string)$mnStoreGoodsQuantity);
        $new_num=bcadd((string)$num, (string)$mnStoreGoodsNum);
        $rep= Goodsbatch::instance()->info([
                'cid'=>$cid,
                'mn_sid'=>$mn_sid,
                'goods_id'=>$goods_id,
                'storage_id'=>$storage['id'],
                'batch_no'=>$batch_no,
                'type'=>1
            ]);
        try{
            
            if($rep){
                $goodsbatchresult= GoodsBatch::instance()->where(['id'=>$rep['id']])->increment('num',$num);
                if(!$goodsbatchresult){
                    return Normal::returnCode(Normal::FAIL,'处理库存批次失败');
                }
                if($rep['stock_loc']!=$stock_loc){
                    GoodsBatch::instance()->edit(['id'=>$rep['id']], ['stock_loc'=>$stock_loc]);
                }
                $goodsbatchresult=$rep['id'];
            }else{
                $goodsbatchresult= GoodsBatch::instance()->add([
                    'cd'=>$time,
                    'cid'=>$cid,
                    'mn_sid'=>$mn_sid,
                    'batch_no'=>$batch_no,
                    'goods_id'=>$goods_id,
                    'storage_id'=>$storage['id'],
                    'storage_code'=>$storage['code'],
                    'storage_name'=>$storage['name'],
                    'num'=>$num,
                    'type'=>1,
                    'quantity'=>$num,
                    'expired_date'=>$expire?strtotime($expire):0,
                    'bill_type'=>$bill_type,
                    'bill_id'=>$bill_id,
                    'bill_code'=>$bill_code,
                    'spec_list'=> json_encode($spec_list,JSON_UNESCAPED_UNICODE),
                    'stock_loc'=>$stock_loc
                ]);
                if(!$goodsbatchresult){
                    return Normal::returnCode(Normal::FAIL,'处理库存批次失败');
                }
            }
            /**
             * 处理小店商品库存表
             */
            if($mnstoregoodsre){
                if($mn_user['stock_share']==1){
                    $brands= GoodsBrand::instance()->info(['id'=>$goodsdata['brand_id']]);
//                    $mnstoregoodsdata=['quantity'=> $new_quantity,'storestatus'=>1,'num'=>$new_num];
                    $mnstoregoodsdata=['storestatus'=>1,'md'=>time()];
                    $mnstoregoodsQuantity=MnStoreGoods::instance()->where(['id'=>$mnstoregoodsre['id']])->increment('quantity',$num);
                    if(!$mnstoregoodsQuantity){
                        return Normal::returnCode(Normal::FAIL,'真实库存处理失败');
                    }
                    $mnstoregoodsNum=MnStoreGoods::instance()->where(['id'=>$mnstoregoodsre['id']])->increment('num',$num);
                    if(!$mnstoregoodsNum){
                        return Normal::returnCode(Normal::FAIL,'可用库存处理失败');
                    }
                    $esdata[]=[
                        'name'=>$goodsdata['name'],
                        'goodsId'=>$goods_id,
                        'classifyID'=>$goodsdata['class_id'],
                        'storeID'=>$mn_sid,
                        'brandName'=>$brands['name'],
                        //'isActive'=>1,
                        'id'=>$mnstoregoodsre['id'],
                        'channelID'=>$cid,
                        'isTrade'=>$goodsdata['is_trade'],
                        'isChannelGoodsActive'=>false,
                        'isStoreGoodsActive'=>true,
                    ];
                    if($goodsdata['is_bonded']!=1){
                        EsPublishMsgService::instance()->storeESMessageProducer([
                            'datas'=>$esdata,
                            'actionType'=>'CommodityChange'
                        ]);
                    }
                }else{
//                    $mnstoregoodsdata=['quantity'=> $new_quantity,'storestatus'=>1];
                    $mnstoregoodsdata=['storestatus'=>1,'md'=>time()];
                    $mnstoregoodsQuantity=MnStoreGoods::instance()->where(['id'=>$mnstoregoodsre['id']])->increment('quantity',$num);
                    if(!$mnstoregoodsQuantity){
                        return Normal::returnCode(Normal::FAIL,'真实库存处理失败');
                    }
                }
                /**
                 * 入库时成本价平均加权
                 */
                if($bill_type==1){
                    $totaloldnum= bcadd((string)$mnstoregoodsre['onlinequantity'],(string) $mnstoregoodsre['quantity']);
                    $totaloldmoney= bcmul((string)$totaloldnum,(string) $mnstoregoodsre['average_price'],3);
                    $totalnewmoney= bcmul((string)$num, (string)$extra['price'],3);
                    $totalmoney= bcadd((string)$totaloldmoney, (string)$totalnewmoney,3);
                    $totalnum= bcadd((string)$totaloldnum, (string)$num);
                    $average_price= $totalmoney==0?0:round(bcdiv((string)$totalmoney, (string)$totalnum,3),2);
                    $mnstoregoodsdata['average_price']=$average_price;
                    $manager_id=$extra['manager_id']??0;
                    AveragePriceLog::instance()->add([
                        'cd'=>time(),
                        'cid'=>$cid,
                        'mn_sid'=>$mn_sid,
                        'goods_id'=>$goods_id,
                        'mn_store_goods_id'=>$mnstoregoodsre['id'],
                        'average_price'=>$average_price,
                        'remark'=>'入库',
                        'type'=>1,
                        'bill_id'=>$bill_id,
                        'bill_code'=>$bill_code,
                        'manager_id'=>$manager_id
                    ]);
                }
                if($goodsdata['is_bonded']==1){
                    $mnstoregoodsdata['bonded_store']=1;
                }
                $mnstoregoodsresult= MnStoreGoods::instance()->edit(['id'=>$mnstoregoodsre['id']],$mnstoregoodsdata);
                $mnstoregoodsid=$mnstoregoodsre['id'];
            }else{
                $mnstoregoodsresult= MnStoreGoods::instance()->add([
                    'df'=>0,
                    'mnid'=>2,
                    'mid'=>$mn_user['mid'],
                    'mn_sid'=>$mn_sid,
                    'price'=>$goodsdata['price_recommend'],
                    'price_vip'=>$goodsdata['price_recommend_vip'],
                    'goods_id'=>$goods_id,
                    'cd'=>$time,
                    'status'=>0,
                    'type'=>2,
                    'quantity'=>$num,
                    'num'=>$mn_user['stock_share']==1?$num:0,
                    'storestatus'=>1,
                    'average_price'=>$bill_type==1?$extra['price']:0,
                    'bonded_store'=>$goodsdata['is_bonded']==1?1:0
                ]);
                $mnstoregoodsid=$mnstoregoodsresult;
            }

            //此处在try、cache里，不用判断，因为可能有相同的商品更新条数为零
            /*if(!$mnstoregoodsresult){
                return Normal::returnCode(Normal::FAIL,'处理小店库存失败');
            }*/
            StockLog::instance()->add([
                'cid'=>$cid,
                'mn_sid'=>$mn_sid,
                'mnstoregoods_id'=>$mnstoregoodsid,
                'goods_id'=>$goods_id,
                'batch_id'=>$goodsbatchresult,
                'quantity'=>$num,
                'type'=>$bill_type==3?3:1,
                'bill_id'=>$bill_id,
                'bill_code'=>$bill_code,
                'status'=>1,
                'remarks'=>$bill_type==3?'销售退货入库':'入库',
                'cd'=>$time,
                'manager_id'=>$extra['manager_id']??0
            ]);
            if(isset($mnstoregoodsre['notice_storage'])&&$mnstoregoodsre['notice_storage']>0){
                Goods::instance()->where(['id'=>$goods_id])->increment('notice_storage',$mnstoregoodsre['notice_storage']);
            }
            return Normal::returnCode(Normal::SUC,'操作成功',['batch_id'=>$goodsbatchresult]);
        } catch (\Exception $ex) {
            return Normal::returnCode(Normal::FAIL,'处理库存失败'.$ex->getMessage());
        }
    }
    
    public function getStockBySearch(int $cid,int $mn_sid,int $manager_id,array $body) {
        $page       = $body['page'] ?? 1;
        $limit      = $body['limit'] ??10;
        $mn_user    = MnUserService::getMnUserInfoByMnSid($mn_sid);
        $mn_user_type = $mn_user['type'];
        $mn_level     = $mn_user['level'];
        $select = [
            'msg.*',
            'g.name',
            'g.skucode',
            'g.barcode',
            'g.price_store',
            'g.class_id',
            'g.img',
            'g.body',
            'g.cid',
            'gc.name as classname',
            'g.origin',
            'g.is_bonded',
            'g.tax_rate',
            'g.tax_free',
            'gb.name as brandname',
            'g.brand_id',
            'g.supplier_skucode'
        ];
        $table = MnStoreGoods::instance()->getTable();
        $query = MnStoreGoods::instance()
        ->from("{$table} as msg")
        ->join('ly_goods as g','msg.goods_id','=','g.id')
        ->leftjoin('ly_goods_class as gc','gc.id','=','g.class_id')
        ->leftjoin('ly_goods_brand as gb','gb.id','=','g.brand_id');
        $query->where('msg.mn_sid',$mn_sid);
        
        //前置仓库
        if( $mn_user_type == Mnuser::TYPE_STORE_QZ ) {
            $query->where(function($query)
            {
                $query->orWhere(function($query){
                    $query->whereIn('g.is_bonded',['0','3'])
                    ->where('g.df',0)
                    ->where('g.status',1)
                    ->where('g.is_trade',1);
                })
                ->orWhere(function($query){
                    $query->where('g.is_bonded',1)
                    ->where('g.df',0)
                    ->where('g.status',1)
                    ->where('msg.bonded_store',1);
                });
            });
        } else {
            $query->whereIn('g.is_bonded',['0','3'])->where('g.is_trade',1);
        }
        if ( isset($body['search']) && !empty($body['search']) ) {
            $search = $body['search'];
            $query->where(function($query) use ($search)
            {
                $query->orWhere('g.skucode','like',"%{$search}%")
                ->orWhere('g.barcode','like',"%{$search}%")
                ->orWhere('g.name','like',"%{$search}%");
            });
            StockSearchHistoryService::instance()->addSearchHistory($cid, $mn_sid, $manager_id, $search);
        }
        $pageInfo = $query->paginate((int)$limit,$select, 'page', (int)$page,true)->toArray();
        $list = $pageInfo['data'];
        
        //计算商品收益率
        $goodsIds = array_column($list,'goods_id');
        $profitGoodsPriceLists = MnGoodsService::instance()->getGoodsAllProfit($mn_sid, $goodsIds,1,$mn_level);
        $profitGoodsPriceListMap = array_column($profitGoodsPriceLists,null,'goods_id');
        
        //商品批次
        $GoodsBatchTable = GoodsBatch::instance()->getTable();
        $goodsBatchList = GoodsBatch::instance()
        ->from("{$GoodsBatchTable} as gb")
        ->select([
            'gb.id',
            'gb.goods_id',
            'gb.batch_no',
            'gb.num',
            'gb.expired_date',
            'gb.stock_loc',
            'psl.code'
        ])
        ->leftjoin('ly_pda_stock_loc as psl','gb.stock_loc','=','psl.id')
        ->where('gb.mn_sid',$mn_sid)
        ->whereIn('gb.goods_id',$goodsIds)
        ->where('gb.num','>',0)
        ->where('gb.type','=',1)
        ->get()
        ->toArray();
        $allStockLoc= PdaStockLoc::instance()->where('mn_sid',$mn_sid)->get()->toArray();
        $allStockLocMap=empty($allStockLoc)?[]: array_column($allStockLoc, 'code','id');
        foreach ($goodsBatchList as $key => $value) {
            $goodsBatchList[$key]['expired_date']=$value['expired_date']?date('Ymd',$value['expired_date']):'';
            $goodsBatchList[$key]['stock_loc']=isset($allStockLocMap[$value['stock_loc']])?$allStockLocMap[$value['stock_loc']]:'默认库位';
        }
        $goodsBatchListMap = GoodsBatchService::instance()->getMapList($goodsBatchList);
        $data   = [];
        foreach ($list as $key => $value) 
        {
            $goods_id               = $value['goods_id'];
            $profit                 = $profitGoodsPriceListMap[$goods_id] ?? [];
            $value['price_store']   = $profit['price_store'] ?? '0.00';
            $price                  = bcadd((string)$value['price_store'],(string)$profit['profit']?? '0.00',2);
            $price_vip              = bcadd((string)$value['price_store'],(string)$profit['profit_vip']?? '0.00',2);
            $price_tax              =0;
            $price_vip_tax          =0;
            $price_total            =$price;
            $price_vip_total        =$price_vip;
            
            if( $value['is_bonded']==1) 
            {
                if( $value['tax_free']== 0 ) {
                    $price_tax          = bcmul((string)$price, (string)$value['tax_rate'],3);
                    $price_vip_tax      = bcmul((string)$price_vip, (string)$value['tax_rate'],3);
                    $price_tax          = number_format((float)$price_tax,2,'.','');
                    $price_vip_tax      = number_format((float)$price_vip_tax,2,'.','');
                    $price_total        = bcadd((string)$price_tax, (string)$price,2);
                    $price_vip_total    = bcadd((string)$price_vip_tax,(string) $price_vip,2);
                }else{
                    $taxflag            = bcadd('1', (string)$value['tax_rate'],3);
                    $price              = bcdiv((string)$price, (string)$taxflag, 3);
                    $price_vip          = bcdiv((string)$price_vip, (string)$taxflag, 3);
                    $price              = number_format((float)$price,2,'.','');
                    $price_vip          = number_format((float)$price_vip,2,'.','');
                    $price_tax          = bcsub((string)$price_total, (string)$price,2);
                    $price_vip_tax      = bcsub((string)$price_vip_total, (string)$price_vip,2);
                }
            }
            
            $data[$key] = [
                'goods_id'          => $value['goods_id'],
                'mn_store_goods_id' => $value['id'],
                'name'              => $value['name'],
                'skucode'           => $value['skucode'],
                'supplier_skucode'  => $value['supplier_skucode'],
                'barcode'           => $value['barcode'],
                'storestatus'       => $value['storestatus'],
                'price'             => $price_total,
                'stock'             => $value['quantity'],
                'price_vip'         => $price_vip_total,
                'class_id'          => $value['class_id'],
                'class_name'        => $value['classname'],
                'brand_id'          => $value['brand_id'],
                'brand_name'        => $value['brandname'],
                'img'               => $value['img'],
                'is_bonded'         => $value['is_bonded'],
                'is_bonded_name'    => Goods::$is_bonded[$value['is_bonded']],
                'batch'             => $goodsBatchListMap[$goods_id] ?? [],
            ];
        }
        
        return Normal::returnCode(Normal::SUC,'获取成功',[
            'list'          => $data,
            'totalcount'    => $pageInfo['total']
        ]);
    }
    
    public function getStockLoc(int $cid,int $mn_sid,array $body) {
        $query= PdaStockLoc::instance()->where('cid',$cid)->where('mn_sid',$mn_sid)->where('df',0)->where('status',1);
        if(isset($body['search'])&&$body['search']!=''){
            $query->where('code','like',"%".$body['search'].'%');
        }
        $list=$query->get()->toArray();
        return Normal::returnCode(Normal::SUC,'操作成功',$list);
    }
}
